package org.beyondhc.lessons.observer;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Logger;

import junit.framework.TestCase;

import org.beyondhc.test.LogMsgCaptor;
import org.junit.Test;

/**
 * 
 * Shows how to (badly) use Java Observer-Observable. This is bit more complex
 * example than BadObserver.
 * 
 * @author Jaana Kulmala
 * 
 */
public class BadObserverLater extends TestCase {

    public class Boss implements Observer {

        @Override
        public void update(final Observable observable, final Object arg) {
            if (observable instanceof ZooKeeper) {
                ((ZooKeeper) observable).getStatusReport();
            }

            LOGGER.info("I hate being bugged with little things");
        }

    }

    public class Koala extends Observable {

        public void setHungry(final boolean isHungry) {
            setChanged();
            notifyObservers(isHungry);
        }

        @Override
        public String toString() {
            return "koala";
        }
    }

    public class WaterPipe extends Observable {

        public void setBroken(final boolean isBroken) {
            setChanged();
            notifyObservers(isBroken);
        }

        @Override
        public String toString() {
            return "watering system";
        }
    }

    public class ZooKeeper extends Observable implements Observer {

        public void getStatusReport() {
            LOGGER.info("Well, I have taken care of everything");
        }

        @Override
        public void update(final Observable observable, final Object arg) {
            final boolean argIsTrue = Boolean.TRUE.equals(arg);
            if (observable instanceof Koala && argIsTrue) {
                LOGGER.info("The lazy critter is hungry again, I cannot believe how much it eats");
            }
            else if (observable instanceof WaterPipe && argIsTrue) {
                LOGGER.info("I'll do what needs to be done");
            }

            if (argIsTrue) {
                setChanged();
                notifyObservers();
            }
        }
    }

    private static final transient Logger LOGGER = Logger
            .getLogger(BadObserverLater.class.getName());

    private List<Koala> initKoalas() {
        final List<Koala> koalas = new ArrayList<Koala>();
        for (int i = 0; i < 15; i++) {
            koalas.add(new Koala());
        }
        return koalas;
    }

    @Test
    public void testEverythingGetsDone() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final List<Koala> fifteenKoalas = initKoalas();
        final WaterPipe pipe = new WaterPipe();
        final ZooKeeper zooKeeper = new ZooKeeper();
        final Boss boss = new Boss();
        zooKeeper.addObserver(boss);
        pipe.addObserver(boss);

        for (final Koala koala : fifteenKoalas) {
            koala.addObserver(boss);
            koala.addObserver(zooKeeper);
        }

        // Problem no 1: the pipe is not fixed
        pipe.setBroken(true);
        assertEquals("Boss just complains, he's not fixing the pipe",
                "I hate being bugged with little things", logMsgCaptor.getMsg());

        // Problem no 2: there are extra notifs
        fifteenKoalas.get(0).setHungry(true);

        assertEquals(
                "First, the koala notification gets through",
                "The lazy critter is hungry again, I cannot believe how much it eats",
                logMsgCaptor.getMsg(2, 5));
        assertEquals("Second, situation is reported to boss",
                "Well, I have taken care of everything",
                logMsgCaptor.getMsg(3, 5));
        assertEquals(
                "Third, the boss says what he always says after being notified",
                "I hate being bugged with little things",
                logMsgCaptor.getMsg(4, 5));
        assertEquals("Fourth, the boss is bothered for no reason",
                "I hate being bugged with little things",
                logMsgCaptor.getMsg(5, 5));

        // Problem no 3: the boss cannot feed the koalas
    };
}
